home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectShow / BaseClasses / wxutil.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-08  |  32.3 KB  |  1,211 lines

  1. //------------------------------------------------------------------------------
  2. // File: WXUtil.cpp
  3. //
  4. // Desc: DirectShow base classes - implements helper classes for building
  5. //       multimedia filters.
  6. //
  7. // Copyright (c) 1992-2001 Microsoft Corporation.  All rights reserved.
  8. //------------------------------------------------------------------------------
  9.  
  10.  
  11. #include <streams.h>
  12.  
  13. //
  14. //  Declare function from largeint.h we need so that PPC can build
  15. //
  16.  
  17. //
  18. // Enlarged integer divide - 64-bits / 32-bits > 32-bits
  19. //
  20.  
  21. #ifndef _X86_
  22.  
  23. #define LLtoU64(x) (*(unsigned __int64*)(void*)(&(x)))
  24.  
  25. __inline
  26. ULONG
  27. WINAPI
  28. EnlargedUnsignedDivide(
  29.     IN ULARGE_INTEGER Dividend,
  30.     IN ULONG Divisor,
  31.     IN PULONG Remainder
  32.     ) {
  33.     // return remainder if necessary
  34.     if(Remainder != NULL)
  35.         *Remainder = (ULONG)(LLtoU64(Dividend) % Divisor);
  36.     return (ULONG)(LLtoU64(Dividend) / Divisor);
  37. }
  38.  
  39. #else
  40. __inline
  41. ULONG
  42. WINAPI
  43. EnlargedUnsignedDivide(
  44.     IN ULARGE_INTEGER Dividend,
  45.     IN ULONG Divisor,
  46.     IN PULONG Remainder
  47.     ) {
  48.     ULONG ulResult;
  49.     _asm {
  50.         mov eax,Dividend.LowPart
  51.         mov edx,Dividend.HighPart
  52.         mov ecx,Remainder
  53.         div Divisor
  54.         or  ecx,ecx
  55.         jz  short label
  56.             mov [ecx],edx
  57.             label:
  58.         mov ulResult,eax
  59.     }
  60.     return ulResult;
  61. }
  62. #endif
  63.  
  64. // --- CAMEvent -----------------------
  65. CAMEvent::CAMEvent(BOOL fManualReset) {
  66.     m_hEvent = CreateEvent(NULL, fManualReset, FALSE, NULL);
  67. }
  68.  
  69. CAMEvent::~CAMEvent() {
  70.     if(m_hEvent) {
  71.         EXECUTE_ASSERT(CloseHandle(m_hEvent));
  72.     }
  73. }
  74.  
  75.  
  76. // --- CAMMsgEvent -----------------------
  77. // One routine.  The rest is handled in CAMEvent
  78.  
  79. BOOL CAMMsgEvent::WaitMsg(DWORD dwTimeout) {
  80.     // wait for the event to be signalled, or for the
  81.     // timeout (in MS) to expire.  allow SENT messages
  82.     // to be processed while we wait
  83.     DWORD dwWait;
  84.     DWORD dwStartTime=0;
  85.  
  86.     // set the waiting period.
  87.     DWORD dwWaitTime = dwTimeout;
  88.  
  89.     // the timeout will eventually run down as we iterate
  90.     // processing messages.  grab the start time so that
  91.     // we can calculate elapsed times.
  92.     if(dwWaitTime != INFINITE) {
  93.         dwStartTime = timeGetTime();
  94.     }
  95.  
  96.     do {
  97.         dwWait = MsgWaitForMultipleObjects(1,&m_hEvent,FALSE, dwWaitTime, QS_SENDMESSAGE);
  98.         if(dwWait == WAIT_OBJECT_0 + 1) {
  99.             MSG Message;
  100.             PeekMessage(&Message,NULL,0,0,PM_NOREMOVE);
  101.  
  102.             // If we have an explicit length of time to wait calculate
  103.             // the next wake up point - which might be now.
  104.             // If dwTimeout is INFINITE, it stays INFINITE
  105.             if(dwWaitTime != INFINITE) {
  106.  
  107.                 DWORD dwElapsed = timeGetTime()-dwStartTime;
  108.  
  109.                 dwWaitTime =
  110.                     (dwElapsed >= dwTimeout)
  111.                     ? 0  // wake up with WAIT_TIMEOUT
  112.                     : dwTimeout-dwElapsed;
  113.             }
  114.         }
  115.     } while(dwWait == WAIT_OBJECT_0 + 1);
  116.  
  117.     // return TRUE if we woke on the event handle,
  118.     //        FALSE if we timed out.
  119.     return (dwWait == WAIT_OBJECT_0);
  120. }
  121.  
  122. // --- CAMThread ----------------------
  123.  
  124.  
  125. CAMThread::CAMThread()
  126.     : m_EventSend(TRUE)     // must be manual-reset for CheckRequest()
  127. {
  128.     m_hThread = NULL;
  129. }
  130.  
  131. CAMThread::~CAMThread() {
  132.     Close();
  133. }
  134.  
  135.  
  136. // when the thread starts, it calls this function. We unwrap the 'this'
  137. //pointer and call ThreadProc.
  138. DWORD WINAPI
  139. CAMThread::InitialThreadProc(LPVOID pv) {
  140.     HRESULT hrCoInit = CAMThread::CoInitializeHelper();
  141.     if(FAILED(hrCoInit)) {
  142.         DbgLog((LOG_ERROR, 1, TEXT("CoInitializeEx failed.")));
  143.     }
  144.  
  145.     CAMThread * pThread = (CAMThread *) pv;
  146.  
  147.     HRESULT hr = pThread->ThreadProc();
  148.  
  149.     if(SUCCEEDED(hrCoInit)) {
  150.         CoUninitialize();
  151.     }
  152.  
  153.     return hr;
  154. }
  155.  
  156. BOOL
  157. CAMThread::Create() {
  158.     DWORD threadid;
  159.  
  160.     CAutoLock lock(&m_AccessLock);
  161.  
  162.     if(ThreadExists()) {
  163.         return FALSE;
  164.     }
  165.  
  166.     m_hThread = CreateThread(NULL,
  167.         0,
  168.         CAMThread::InitialThreadProc,
  169.         this,
  170.         0,
  171.         &threadid);
  172.  
  173.     if(!m_hThread) {
  174.         return FALSE;
  175.     }
  176.  
  177.     return TRUE;
  178. }
  179.  
  180. DWORD
  181. CAMThread::CallWorker(DWORD dwParam) {
  182.     // lock access to the worker thread for scope of this object
  183.     CAutoLock lock(&m_AccessLock);
  184.  
  185.     if(!ThreadExists()) {
  186.         return (DWORD) E_FAIL;
  187.     }
  188.  
  189.     // set the parameter
  190.     m_dwParam = dwParam;
  191.  
  192.     // signal the worker thread
  193.     m_EventSend.Set();
  194.  
  195.     // wait for the completion to be signalled
  196.     m_EventComplete.Wait();
  197.  
  198.     // done - this is the thread's return value
  199.     return m_dwReturnVal;
  200. }
  201.  
  202. // Wait for a request from the client
  203. DWORD
  204. CAMThread::GetRequest() {
  205.     m_EventSend.Wait();
  206.     return m_dwParam;
  207. }
  208.  
  209. // is there a request?
  210. BOOL
  211. CAMThread::CheckRequest(DWORD * pParam) {
  212.     if(!m_EventSend.Check()) {
  213.         return FALSE;
  214.     }
  215.     else {
  216.         if(pParam) {
  217.             *pParam = m_dwParam;
  218.         }
  219.         return TRUE;
  220.     }
  221. }
  222.  
  223. // reply to the request
  224. void
  225. CAMThread::Reply(DWORD dw) {
  226.     m_dwReturnVal = dw;
  227.  
  228.     // The request is now complete so CheckRequest should fail from
  229.     // now on
  230.     //
  231.     // This event should be reset BEFORE we signal the client or
  232.     // the client may Set it before we reset it and we'll then
  233.     // reset it (!)
  234.  
  235.     m_EventSend.Reset();
  236.  
  237.     // Tell the client we're finished
  238.  
  239.     m_EventComplete.Set();
  240. }
  241.  
  242. HRESULT CAMThread::CoInitializeHelper() {
  243.     // call CoInitializeEx and tell OLE not to create a window (this
  244.     // thread probably won't dispatch messages and will hang on
  245.     // broadcast msgs o/w).
  246.     //
  247.     // If CoInitEx is not available, threads that don't call CoCreate
  248.     // aren't affected. Threads that do will have to handle the
  249.     // failure. Perhaps we should fall back to CoInitialize and risk
  250.     // hanging?
  251.     //
  252.  
  253.     // older versions of ole32.dll don't have CoInitializeEx
  254.  
  255.     HRESULT hr = E_FAIL;
  256.     HINSTANCE hOle = GetModuleHandle(TEXT("ole32.dll"));
  257.     if(hOle) {
  258.         typedef HRESULT(STDAPICALLTYPE *PCoInitializeEx)(
  259.             LPVOID pvReserved, DWORD dwCoInit);
  260.         PCoInitializeEx pCoInitializeEx =
  261.             (PCoInitializeEx)(GetProcAddress(hOle, "CoInitializeEx"));
  262.         if(pCoInitializeEx) {
  263.             hr = (*pCoInitializeEx)(0, COINIT_DISABLE_OLE1DDE );
  264.         }
  265.     }
  266.     else {
  267.         // caller must load ole32.dll
  268.         DbgBreak("couldn't locate ole32.dll");
  269.     }
  270.  
  271.     return hr;
  272. }
  273.  
  274.  
  275. // destructor for CMsgThread  - cleans up any messages left in the
  276. // queue when the thread exited
  277. CMsgThread::~CMsgThread() {
  278.     if(m_hThread != NULL) {
  279.         WaitForSingleObject(m_hThread, INFINITE);
  280.         EXECUTE_ASSERT(CloseHandle(m_hThread));
  281.     }
  282.  
  283.     POSITION pos = m_ThreadQueue.GetHeadPosition();
  284.     while(pos) {
  285.         CMsg * pMsg = m_ThreadQueue.GetNext(pos);
  286.         delete pMsg;
  287.     }
  288.     m_ThreadQueue.RemoveAll();
  289.  
  290.     if(m_hSem != NULL) {
  291.         EXECUTE_ASSERT(CloseHandle(m_hSem));
  292.     }
  293. }
  294.  
  295. BOOL
  296. CMsgThread::CreateThread(
  297.     ) {
  298.     m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL);
  299.     if(m_hSem == NULL) {
  300.         return FALSE;
  301.     }
  302.  
  303.     m_hThread = ::CreateThread(NULL, 0, DefaultThreadProc,
  304.         (LPVOID)this, 0, &m_ThreadId);
  305.     return m_hThread != NULL;
  306. }
  307.  
  308.  
  309. // This is the threads message pump.  Here we get and dispatch messages to
  310. // clients thread proc until the client refuses to process a message.
  311. // The client returns a non-zero value to stop the message pump, this
  312. // value becomes the threads exit code.
  313.  
  314. DWORD WINAPI
  315. CMsgThread::DefaultThreadProc(
  316.     LPVOID lpParam
  317.     ) {
  318.     CMsgThread *lpThis = (CMsgThread *)lpParam;
  319.     CMsg msg;
  320.     LRESULT lResult;
  321.  
  322.     // !!!
  323.     CoInitialize(NULL);
  324.  
  325.     // allow a derived class to handle thread startup
  326.     lpThis->OnThreadInit();
  327.  
  328.     do {
  329.         lpThis->GetThreadMsg(&msg);
  330.         lResult = lpThis->ThreadMessageProc(msg.uMsg,msg.dwFlags,
  331.             msg.lpParam, msg.pEvent);
  332.     } while(lResult == 0L);
  333.  
  334.     // !!!
  335.     CoUninitialize();
  336.  
  337.     return (DWORD)lResult;
  338. }
  339.  
  340.  
  341. // Block until the next message is placed on the list m_ThreadQueue.
  342. // copies the message to the message pointed to by *pmsg
  343. void
  344. CMsgThread::GetThreadMsg(CMsg *msg) {
  345.     CMsg * pmsg = NULL;
  346.  
  347.     // keep trying until a message appears
  348.     while(TRUE) { {
  349.             CAutoLock lck(&m_Lock);
  350.             pmsg = m_ThreadQueue.RemoveHead();
  351.             if(pmsg == NULL) {
  352.                 m_lWaiting++;
  353.             }
  354.             else {
  355.                 break;
  356.             }
  357.         }
  358.         // the semaphore will be signalled when it is non-empty
  359.         WaitForSingleObject(m_hSem, INFINITE);
  360.     }
  361.     // copy fields to caller's CMsg
  362.     *msg = *pmsg;
  363.  
  364.     // this CMsg was allocated by the 'new' in PutThreadMsg
  365.     delete pmsg;
  366.  
  367. }
  368.  
  369.  
  370. // NOTE: as we need to use the same binaries on Win95 as on NT this code should
  371. // be compiled WITHOUT unicode being defined.  Otherwise we will not pick up
  372. // these internal routines and the binary will not run on Win95.
  373.  
  374. #ifndef UNICODE
  375.  
  376. #pragma warning(disable:4706)  // C4706: assignment within conditional expression
  377.  
  378. // Windows 95 doesn't implement this, so we provide an implementation.
  379. LPWSTR
  380. WINAPI
  381. lstrcpyWInternal(
  382.     LPWSTR lpString1,
  383.     LPCWSTR lpString2
  384.     ) {
  385.     LPWSTR  lpReturn = lpString1;
  386.     while(*lpString1++ = *lpString2++);
  387.  
  388.     return lpReturn;
  389. }
  390.  
  391. // Windows 95 doesn't implement this, so we provide an implementation.
  392. LPWSTR
  393. WINAPI
  394. lstrcpynWInternal(
  395.     LPWSTR lpString1,
  396.     LPCWSTR lpString2,
  397.     int     iMaxLength
  398.     ) {
  399.     ASSERT(iMaxLength);
  400.     LPWSTR  lpReturn = lpString1;
  401.     if(iMaxLength) {
  402.         while(--iMaxLength && (*lpString1++ = *lpString2++));
  403.  
  404.         // If we ran out of room (which will be the case if
  405.         // iMaxLength is now 0) we still need to terminate the
  406.         // string.
  407.         if(!iMaxLength) *lpString1 = L'\0';
  408.     }
  409.     return lpReturn;
  410. }
  411.  
  412. #pragma warning(default:4706)  // C4706: assignment within conditional expression
  413.  
  414. int
  415. WINAPI
  416. lstrcmpWInternal(
  417.     LPCWSTR lpString1,
  418.     LPCWSTR lpString2
  419.     ) {
  420.     do {
  421.         WCHAR c1 = *lpString1;
  422.         WCHAR c2 = *lpString2;
  423.         if(c1 != c2)
  424.             return (int) c1 - (int) c2;
  425.     } while(*lpString1++ && *lpString2++);
  426.     return 0;
  427. }
  428.  
  429.  
  430. int
  431. WINAPI
  432. lstrcmpiWInternal(
  433.     LPCWSTR lpString1,
  434.     LPCWSTR lpString2
  435.     ) {
  436.     do {
  437.         WCHAR c1 = *lpString1;
  438.         WCHAR c2 = *lpString2;
  439.         if(c1 >= L'A' && c1 <= L'Z')
  440.             c1 -= (WCHAR) (L'A' - L'a');
  441.         if(c2 >= L'A' && c2 <= L'Z')
  442.             c2 -= (WCHAR) (L'A' - L'a');
  443.  
  444.         if(c1 != c2)
  445.             return (int) c1 - (int) c2;
  446.     } while(*lpString1++ && *lpString2++);
  447.  
  448.     return 0;
  449. }
  450.  
  451.  
  452. int
  453. WINAPI
  454. lstrlenWInternal(
  455.     LPCWSTR lpString
  456.     ) {
  457.     int i = -1;
  458.     while(*(lpString+(++i)))
  459.         ;
  460.     return i;
  461. }
  462.  
  463.  
  464. int WINAPIV wsprintfWInternal(LPWSTR wszOut, LPCWSTR pszFmt, ...) {
  465.     char fmt[256]; // !!!
  466.     char ach[256]; // !!!
  467.     int i;
  468.  
  469.     va_list va;
  470.     va_start(va, pszFmt);
  471.     WideCharToMultiByte(GetACP(), 0, pszFmt, -1, fmt, 256, NULL, NULL);
  472.     i = wvsprintfA(ach, fmt, va);
  473.     va_end(va);
  474.  
  475.     MultiByteToWideChar(CP_ACP, 0, ach, -1, wszOut, i+1);
  476.  
  477.     return i;
  478. }
  479. #else
  480.  
  481. // need to provide the implementations in unicode for non-unicode
  482. // builds linking with the unicode strmbase.lib
  483. LPWSTR WINAPI lstrcpyWInternal(
  484.     LPWSTR lpString1,
  485.     LPCWSTR lpString2
  486.     ) {
  487.     return lstrcpyW(lpString1, lpString2);
  488. }
  489.  
  490. LPWSTR WINAPI lstrcpynWInternal(
  491.     LPWSTR lpString1,
  492.     LPCWSTR lpString2,
  493.     int     iMaxLength
  494.     ) {
  495.     return lstrcpynW(lpString1, lpString2, iMaxLength);
  496. }
  497.  
  498. int WINAPI lstrcmpWInternal(
  499.     LPCWSTR lpString1,
  500.     LPCWSTR lpString2
  501.     ) {
  502.     return lstrcmpW(lpString1, lpString2);
  503. }
  504.  
  505.  
  506. int WINAPI lstrcmpiWInternal(
  507.     LPCWSTR lpString1,
  508.     LPCWSTR lpString2
  509.     ) {
  510.     return lstrcmpiW(lpString1, lpString2);
  511. }
  512.  
  513.  
  514. int WINAPI lstrlenWInternal(
  515.     LPCWSTR lpString
  516.     ) {
  517.     return lstrlenW(lpString);
  518. }
  519.  
  520.  
  521. int WINAPIV wsprintfWInternal(
  522.     LPWSTR wszOut, LPCWSTR pszFmt, ...) {
  523.     va_list va;
  524.     va_start(va, pszFmt);
  525.     int i = wvsprintfW(wszOut, pszFmt, va);
  526.     va_end(va);
  527.     return i;
  528. }
  529. #endif
  530.  
  531.  
  532. // Helper function - convert int to WSTR
  533. void WINAPI IntToWstr(int i, LPWSTR wstr) {
  534. #ifdef UNICODE
  535.     wsprintf(wstr, L"%d", i);
  536. #else
  537.     TCHAR temp[32];
  538.     wsprintf(temp, "%d", i);
  539.     MultiByteToWideChar(CP_ACP, 0, temp, -1, wstr, 32);
  540. #endif
  541. } // IntToWstr
  542.  
  543.  
  544. #if 0
  545. void * memchrInternal(const void *pv, int c, size_t sz) {
  546.     BYTE *pb = (BYTE *) pv;
  547.     while(sz--) {
  548.         if(*pb == c)
  549.             return (void *) pb;
  550.         pb++;
  551.     }
  552.     return NULL;
  553. }
  554. #endif
  555.  
  556.  
  557. #define MEMORY_ALIGNMENT        4
  558. #define MEMORY_ALIGNMENT_LOG2   2
  559. #define MEMORY_ALIGNMENT_MASK   MEMORY_ALIGNMENT - 1
  560.  
  561. void * __stdcall memmoveInternal(void * dst, const void * src, size_t count) {
  562.     void * ret = dst;
  563.  
  564. #ifdef _X86_
  565.     if(dst <= src || (char *)dst >= ((char *)src + count)) {
  566.  
  567.         /*
  568.         * Non-Overlapping Buffers
  569.         * copy from lower addresses to higher addresses
  570.         */
  571.         _asm {
  572.             mov     esi,src
  573.             mov     edi,dst
  574.             mov     ecx,count
  575.             cld
  576.             mov     edx,ecx
  577.             and     edx,MEMORY_ALIGNMENT_MASK
  578.             shr     ecx,MEMORY_ALIGNMENT_LOG2
  579.             rep     movsd
  580.             or      ecx,edx
  581.             jz      memmove_done
  582.             rep     movsb
  583.             memmove_done:
  584.         }
  585.     }
  586.     else {
  587.  
  588.         /*
  589.         * Overlapping Buffers
  590.         * copy from higher addresses to lower addresses
  591.         */
  592.         _asm {
  593.             mov     esi,src
  594.             mov     edi,dst
  595.             mov     ecx,count
  596.             std
  597.             add     esi,ecx
  598.             add     edi,ecx
  599.             dec     esi
  600.             dec     edi
  601.             rep     movsb
  602.             cld
  603.         }
  604.     }
  605. #else
  606.     MoveMemory(dst, src, count);
  607. #endif
  608.  
  609.     return ret;
  610. }
  611.  
  612. /*  Arithmetic functions to help with time format conversions
  613. */
  614.  
  615. #ifdef _M_ALPHA
  616. // work around bug in version 12.00.8385 of the alpha compiler where
  617. // UInt32x32To64 sign-extends its arguments (?)
  618. #undef UInt32x32To64
  619. #define UInt32x32To64(a, b) (((ULONGLONG)((ULONG)(a)) & 0xffffffff) * ((ULONGLONG)((ULONG)(b)) & 0xffffffff))
  620. #endif
  621.  
  622. /*   Compute (a * b + d) / c */
  623. LONGLONG WINAPI llMulDiv(LONGLONG a, LONGLONG b, LONGLONG c, LONGLONG d) {
  624.     /*  Compute the absolute values to avoid signed arithmetic problems */
  625.     ULARGE_INTEGER ua, ub;
  626.     DWORDLONG uc;
  627.  
  628.     ua.QuadPart = (DWORDLONG)(a >= 0 ? a : -a);
  629.     ub.QuadPart = (DWORDLONG)(b >= 0 ? b : -b);
  630.     uc          = (DWORDLONG)(c >= 0 ? c : -c);
  631.     BOOL bSign = (a < 0) ^ (b < 0);
  632.  
  633.     /*  Do long multiplication */
  634.     ULARGE_INTEGER p[2];
  635.     p[0].QuadPart  = UInt32x32To64(ua.LowPart, ub.LowPart);
  636.  
  637.     /*  This next computation cannot overflow into p[1].HighPart because
  638.     the max number we can compute here is:
  639.  
  640.     (2 ** 32 - 1) * (2 ** 32 - 1) +  // ua.LowPart * ub.LowPart
  641.     (2 ** 32) *  (2 ** 31) * (2 ** 32 - 1) * 2    // x.LowPart * y.HighPart * 2
  642.  
  643.     == 2 ** 96 - 2 ** 64 + (2 ** 64 - 2 ** 33 + 1)
  644.     == 2 ** 96 - 2 ** 33 + 1
  645.     < 2 ** 96
  646.     */
  647.  
  648.     ULARGE_INTEGER x;
  649.     x.QuadPart     = UInt32x32To64(ua.LowPart, ub.HighPart) +
  650.         UInt32x32To64(ua.HighPart, ub.LowPart) +
  651.         p[0].HighPart;
  652.     p[0].HighPart  = x.LowPart;
  653.     p[1].QuadPart  = UInt32x32To64(ua.HighPart, ub.HighPart) + x.HighPart;
  654.  
  655.     if(d != 0) {
  656.         ULARGE_INTEGER ud[2];
  657.         if(bSign) {
  658.             ud[0].QuadPart = (DWORDLONG)(-d);
  659.             if(d > 0) {
  660.                 /*  -d < 0 */
  661.                 ud[1].QuadPart = (DWORDLONG)(LONGLONG)-1;
  662.             }
  663.             else {
  664.                 ud[1].QuadPart = (DWORDLONG)0;
  665.             }
  666.         }
  667.         else {
  668.             ud[0].QuadPart = (DWORDLONG)d;
  669.             if(d < 0) {
  670.                 ud[1].QuadPart = (DWORDLONG)(LONGLONG)-1;
  671.             }
  672.             else {
  673.                 ud[1].QuadPart = (DWORDLONG)0;
  674.             }
  675.         }
  676.         /*  Now do extended addition */
  677.         ULARGE_INTEGER uliTotal;
  678.  
  679.         /*  Add ls DWORDs */
  680.         uliTotal.QuadPart  = (DWORDLONG)ud[0].LowPart + p[0].LowPart;
  681.         p[0].LowPart       = uliTotal.LowPart;
  682.  
  683.         /*  Propagate carry */
  684.         uliTotal.LowPart   = uliTotal.HighPart;
  685.         uliTotal.HighPart  = 0;
  686.  
  687.         /*  Add 2nd most ls DWORDs */
  688.         uliTotal.QuadPart += (DWORDLONG)ud[0].HighPart + p[0].HighPart;
  689.         p[0].HighPart      = uliTotal.LowPart;
  690.  
  691.         /*  Propagate carry */
  692.         uliTotal.LowPart   = uliTotal.HighPart;
  693.         uliTotal.HighPart  = 0;
  694.  
  695.         /*  Add MS DWORDLONGs - no carry expected */
  696.         p[1].QuadPart     += ud[1].QuadPart + uliTotal.QuadPart;
  697.  
  698.         /*  Now see if we got a sign change from the addition */
  699.         if((LONG)p[1].HighPart < 0) {
  700.             bSign = !bSign;
  701.  
  702.             /*  Negate the current value (ugh!) */
  703.             p[0].QuadPart  = ~p[0].QuadPart;
  704.             p[1].QuadPart  = ~p[1].QuadPart;
  705.             p[0].QuadPart += 1;
  706.             p[1].QuadPart += (p[0].QuadPart == 0);
  707.         }
  708.     }
  709.  
  710.     /*  Now for the division */
  711.     if(c < 0) {
  712.         bSign = !bSign;
  713.     }
  714.  
  715.  
  716.     /*  This will catch c == 0 and overflow */
  717.     if(uc <= p[1].QuadPart) {
  718.         return bSign ? (LONGLONG)0x8000000000000000 :
  719.         (LONGLONG)0x7FFFFFFFFFFFFFFF;
  720.     }
  721.  
  722.     DWORDLONG ullResult;
  723.  
  724.     /*  Do the division */
  725.     /*  If the dividend is a DWORD_LONG use the compiler */
  726.     if(p[1].QuadPart == 0) {
  727.         ullResult = p[0].QuadPart / uc;
  728.         return bSign ? -(LONGLONG)ullResult : (LONGLONG)ullResult;
  729.     }
  730.  
  731.     /*  If the divisor is a DWORD then its simpler */
  732.     ULARGE_INTEGER ulic;
  733.     ulic.QuadPart = uc;
  734.     if(ulic.HighPart == 0) {
  735.         ULARGE_INTEGER uliDividend;
  736.         ULARGE_INTEGER uliResult;
  737.         DWORD dwDivisor = (DWORD)uc;
  738.         // ASSERT(p[1].HighPart == 0 && p[1].LowPart < dwDivisor);
  739.         uliDividend.HighPart = p[1].LowPart;
  740.         uliDividend.LowPart = p[0].HighPart;
  741. #ifndef USE_LARGEINT
  742.         uliResult.HighPart = (DWORD)(uliDividend.QuadPart / dwDivisor);
  743.         p[0].HighPart = (DWORD)(uliDividend.QuadPart % dwDivisor);
  744.         uliResult.LowPart = 0;
  745.         uliResult.QuadPart = p[0].QuadPart / dwDivisor + uliResult.QuadPart;
  746. #else
  747.         /*  NOTE - this routine will take exceptions if
  748.         the result does not fit in a DWORD
  749.         */
  750.         if(uliDividend.QuadPart >= (DWORDLONG)dwDivisor) {
  751.             uliResult.HighPart = EnlargedUnsignedDivide(uliDividend,
  752.                 dwDivisor,
  753.                 &p[0].HighPart);
  754.         }
  755.         else {
  756.             uliResult.HighPart = 0;
  757.         }
  758.         uliResult.LowPart = EnlargedUnsignedDivide(p[0],
  759.             dwDivisor,
  760.             NULL);
  761. #endif
  762.         return bSign ? -(LONGLONG)uliResult.QuadPart :
  763.         (LONGLONG)uliResult.QuadPart;
  764.     }
  765.  
  766.  
  767.     ullResult = 0;
  768.  
  769.     /*  OK - do long division */
  770.     for(int i = 0; i < 64; i++) {
  771.         ullResult <<= 1;
  772.  
  773.         /*  Shift 128 bit p left 1 */
  774.         p[1].QuadPart <<= 1;
  775.         if((p[0].HighPart & 0x80000000) != 0) {
  776.             p[1].LowPart++;
  777.         }
  778.         p[0].QuadPart <<= 1;
  779.  
  780.         /*  Compare */
  781.         if(uc <= p[1].QuadPart) {
  782.             p[1].QuadPart -= uc;
  783.             ullResult += 1;
  784.         }
  785.     }
  786.  
  787.     return bSign ? - (LONGLONG)ullResult : (LONGLONG)ullResult;
  788. }
  789.  
  790. LONGLONG WINAPI Int64x32Div32(LONGLONG a, LONG b, LONG c, LONG d) {
  791.     ULARGE_INTEGER ua;
  792.     DWORD ub;
  793.     DWORD uc;
  794.  
  795.     /*  Compute the absolute values to avoid signed arithmetic problems */
  796.     ua.QuadPart = (DWORDLONG)(a >= 0 ? a : -a);
  797.     ub = (DWORD)(b >= 0 ? b : -b);
  798.     uc = (DWORD)(c >= 0 ? c : -c);
  799.     BOOL bSign = (a < 0) ^ (b < 0);
  800.  
  801.     /*  Do long multiplication */
  802.     ULARGE_INTEGER p0;
  803.     DWORD p1;
  804.     p0.QuadPart  = UInt32x32To64(ua.LowPart, ub);
  805.  
  806.     if(ua.HighPart != 0) {
  807.         ULARGE_INTEGER x;
  808.         x.QuadPart     = UInt32x32To64(ua.HighPart, ub) + p0.HighPart;
  809.         p0.HighPart  = x.LowPart;
  810.         p1   = x.HighPart;
  811.     }
  812.     else {
  813.         p1 = 0;
  814.     }
  815.  
  816.     if(d != 0) {
  817.         ULARGE_INTEGER ud0;
  818.         DWORD ud1;
  819.  
  820.         if(bSign) {
  821.             //
  822.             //  Cast d to LONGLONG first otherwise -0x80000000 sign extends
  823.             //  incorrectly
  824.             //
  825.             ud0.QuadPart = (DWORDLONG)(-(LONGLONG)d);
  826.             if(d > 0) {
  827.                 /*  -d < 0 */
  828.                 ud1 = (DWORD)-1;
  829.             }
  830.             else {
  831.                 ud1 = (DWORD)0;
  832.             }
  833.         }
  834.         else {
  835.             ud0.QuadPart = (DWORDLONG)d;
  836.             if(d < 0) {
  837.                 ud1 = (DWORD)-1;
  838.             }
  839.             else {
  840.                 ud1 = (DWORD)0;
  841.             }
  842.         }
  843.         /*  Now do extended addition */
  844.         ULARGE_INTEGER uliTotal;
  845.  
  846.         /*  Add ls DWORDs */
  847.         uliTotal.QuadPart  = (DWORDLONG)ud0.LowPart + p0.LowPart;
  848.         p0.LowPart       = uliTotal.LowPart;
  849.  
  850.         /*  Propagate carry */
  851.         uliTotal.LowPart   = uliTotal.HighPart;
  852.         uliTotal.HighPart  = 0;
  853.  
  854.         /*  Add 2nd most ls DWORDs */
  855.         uliTotal.QuadPart += (DWORDLONG)ud0.HighPart + p0.HighPart;
  856.         p0.HighPart      = uliTotal.LowPart;
  857.  
  858.         /*  Add MS DWORDLONGs - no carry expected */
  859.         p1 += ud1 + uliTotal.HighPart;
  860.  
  861.         /*  Now see if we got a sign change from the addition */
  862.         if((LONG)p1 < 0) {
  863.             bSign = !bSign;
  864.  
  865.             /*  Negate the current value (ugh!) */
  866.             p0.QuadPart  = ~p0.QuadPart;
  867.             p1 = ~p1;
  868.             p0.QuadPart += 1;
  869.             p1 += (p0.QuadPart == 0);
  870.         }
  871.     }
  872.  
  873.     /*  Now for the division */
  874.     if(c < 0) {
  875.         bSign = !bSign;
  876.     }
  877.  
  878.  
  879.     /*  This will catch c == 0 and overflow */
  880.     if(uc <= p1) {
  881.         return bSign ? (LONGLONG)0x8000000000000000 :
  882.         (LONGLONG)0x7FFFFFFFFFFFFFFF;
  883.     }
  884.  
  885.     /*  Do the division */
  886.  
  887.     /*  If the divisor is a DWORD then its simpler */
  888.     ULARGE_INTEGER uliDividend;
  889.     ULARGE_INTEGER uliResult;
  890.     DWORD dwDivisor = uc;
  891.     uliDividend.HighPart = p1;
  892.     uliDividend.LowPart = p0.HighPart;
  893.     /*  NOTE - this routine will take exceptions if
  894.     the result does not fit in a DWORD
  895.     */
  896.     if(uliDividend.QuadPart >= (DWORDLONG)dwDivisor) {
  897.         uliResult.HighPart = EnlargedUnsignedDivide(uliDividend,
  898.             dwDivisor,
  899.             &p0.HighPart);
  900.     }
  901.     else {
  902.         uliResult.HighPart = 0;
  903.     }
  904.     uliResult.LowPart = EnlargedUnsignedDivide(p0,
  905.         dwDivisor,
  906.         NULL);
  907.     return bSign ? -(LONGLONG)uliResult.QuadPart :
  908.     (LONGLONG)uliResult.QuadPart;
  909. }
  910.  
  911. #ifdef DEBUG
  912. /******************************Public*Routine******************************\
  913. * Debug CCritSec helpers
  914. *
  915. * We provide debug versions of the Constructor, destructor, Lock and Unlock
  916. * routines.  The debug code tracks who owns each critical section by
  917. * maintaining a depth count.
  918. *
  919. * History:
  920. *
  921. \**************************************************************************/
  922.  
  923. CCritSec::CCritSec() {
  924.     InitializeCriticalSection(&m_CritSec);
  925.     m_currentOwner = m_lockCount = 0;
  926.     m_fTrace = FALSE;
  927. }
  928.  
  929. CCritSec::~CCritSec() {
  930.     DeleteCriticalSection(&m_CritSec);
  931. }
  932.  
  933. void CCritSec::Lock() {
  934.     UINT tracelevel=3;
  935.     DWORD us = GetCurrentThreadId();
  936.     DWORD currentOwner = m_currentOwner;
  937.     if(currentOwner && (currentOwner != us)) {
  938.         // already owned, but not by us
  939.         if(m_fTrace) {
  940.             DbgLog((LOG_LOCKING, 2, TEXT("Thread %d about to wait for lock %x owned by %d"),
  941.                 GetCurrentThreadId(), &m_CritSec, currentOwner));
  942.             tracelevel=2;
  943.             // if we saw the message about waiting for the critical
  944.             // section we ensure we see the message when we get the
  945.             // critical section
  946.         }
  947.     }
  948.     EnterCriticalSection(&m_CritSec);
  949.     if(0 == m_lockCount++) {
  950.         // we now own it for the first time.  Set owner information
  951.         m_currentOwner = us;
  952.  
  953.         if(m_fTrace) {
  954.             DbgLog((LOG_LOCKING, tracelevel, TEXT("Thread %d now owns lock %x"), m_currentOwner, &m_CritSec));
  955.         }
  956.     }
  957. }
  958.  
  959. void CCritSec::Unlock() {
  960.     if(0 == --m_lockCount) {
  961.         // about to be unowned
  962.         if(m_fTrace) {
  963.             DbgLog((LOG_LOCKING, 3, TEXT("Thread %d releasing lock %x"), m_currentOwner, &m_CritSec));
  964.         }
  965.  
  966.         m_currentOwner = 0;
  967.     }
  968.     LeaveCriticalSection(&m_CritSec);
  969. }
  970.  
  971. void WINAPI DbgLockTrace(CCritSec * pcCrit, BOOL fTrace) {
  972.     pcCrit->m_fTrace = fTrace;
  973. }
  974.  
  975. BOOL WINAPI CritCheckIn(CCritSec * pcCrit) {
  976.     return (GetCurrentThreadId() == pcCrit->m_currentOwner);
  977. }
  978.  
  979. BOOL WINAPI CritCheckIn(const CCritSec * pcCrit) {
  980.     return (GetCurrentThreadId() == pcCrit->m_currentOwner);
  981. }
  982.  
  983. BOOL WINAPI CritCheckOut(CCritSec * pcCrit) {
  984.     return (GetCurrentThreadId() != pcCrit->m_currentOwner);
  985. }
  986.  
  987. BOOL WINAPI CritCheckOut(const CCritSec * pcCrit) {
  988.     return (GetCurrentThreadId() != pcCrit->m_currentOwner);
  989. }
  990. #endif
  991.  
  992.  
  993. STDAPI WriteBSTR(BSTR *pstrDest, LPCWSTR szSrc) {
  994.     *pstrDest = SysAllocString(szSrc);
  995.     if(!(*pstrDest)) return E_OUTOFMEMORY;
  996.     return NOERROR;
  997. }
  998.  
  999.  
  1000. STDAPI FreeBSTR(BSTR* pstr) {
  1001.     if(*pstr == NULL) return S_FALSE;
  1002.     SysFreeString(*pstr);
  1003.     return NOERROR;
  1004. }
  1005.  
  1006.  
  1007. // Return a wide string - allocating memory for it
  1008. // Returns:
  1009. //    S_OK          - no error
  1010. //    E_POINTER     - ppszReturn == NULL
  1011. //    E_OUTOFMEMORY - can't allocate memory for returned string
  1012. STDAPI AMGetWideString(LPCWSTR psz, LPWSTR *ppszReturn) {
  1013.     CheckPointer(ppszReturn, E_POINTER);
  1014.     ValidateReadWritePtr(ppszReturn, sizeof(LPWSTR));
  1015.     DWORD nameLen = sizeof(WCHAR) * (lstrlenW(psz)+1);
  1016.     *ppszReturn = (LPWSTR)CoTaskMemAlloc(nameLen);
  1017.     if(*ppszReturn == NULL) {
  1018.         return E_OUTOFMEMORY;
  1019.     }
  1020.     CopyMemory(*ppszReturn, psz, nameLen);
  1021.     return NOERROR;
  1022. }
  1023.  
  1024. // Waits for the HANDLE hObject.  While waiting messages sent
  1025. // to windows on our thread by SendMessage will be processed.
  1026. // Using this function to do waits and mutual exclusion
  1027. // avoids some deadlocks in objects with windows.
  1028. // Return codes are the same as for WaitForSingleObject
  1029. DWORD WINAPI WaitDispatchingMessages(
  1030.     HANDLE hObject,
  1031.     DWORD dwWait,
  1032.     HWND hwnd,
  1033.     UINT uMsg,
  1034.     HANDLE hEvent) {
  1035.     BOOL bPeeked = FALSE;
  1036.     DWORD dwResult;
  1037.     DWORD dwStart=0;
  1038.     DWORD dwThreadPriority=0;
  1039.  
  1040.     static UINT uMsgId = 0;
  1041.  
  1042.     HANDLE hObjects[2] = { hObject, hEvent };
  1043.     if(dwWait != INFINITE && dwWait != 0) {
  1044.         dwStart = GetTickCount();
  1045.     }
  1046.     for(; ;) {
  1047.         DWORD nCount = NULL != hEvent ? 2 : 1;
  1048.  
  1049.         //  Minimize the chance of actually dispatching any messages
  1050.         //  by seeing if we can lock immediately.
  1051.         dwResult = WaitForMultipleObjects(nCount, hObjects, FALSE, 0);
  1052.         if(dwResult < WAIT_OBJECT_0 + nCount) {
  1053.             break;
  1054.         }
  1055.  
  1056.         DWORD dwTimeOut = dwWait;
  1057.         if(dwTimeOut > 10) {
  1058.             dwTimeOut = 10;
  1059.         }
  1060.         dwResult = MsgWaitForMultipleObjects(nCount,
  1061.             hObjects,
  1062.             FALSE,
  1063.             dwTimeOut,
  1064.             hwnd == NULL ? QS_SENDMESSAGE :
  1065.         QS_SENDMESSAGE + QS_POSTMESSAGE);
  1066.         if(dwResult == WAIT_OBJECT_0 + nCount ||
  1067.             dwResult == WAIT_TIMEOUT && dwTimeOut != dwWait) {
  1068.             MSG msg;
  1069.             if(hwnd != NULL) {
  1070.                 while(PeekMessage(&msg, hwnd, uMsg, uMsg, PM_REMOVE)) {
  1071.                     DispatchMessage(&msg);
  1072.                 }
  1073.             }
  1074.             // Do this anyway - the previous peek doesn't flush out the
  1075.             // messages
  1076.             PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
  1077.  
  1078.             if(dwWait != INFINITE && dwWait != 0) {
  1079.                 DWORD dwNow = GetTickCount();
  1080.  
  1081.                 // Working with differences handles wrap-around
  1082.                 DWORD dwDiff = dwNow - dwStart;
  1083.                 if(dwDiff > dwWait) {
  1084.                     dwWait = 0;
  1085.                 }
  1086.                 else {
  1087.                     dwWait -= dwDiff;
  1088.                 }
  1089.                 dwStart = dwNow;
  1090.             }
  1091.             if(!bPeeked) {
  1092.                 //  Raise our priority to prevent our message queue
  1093.                 //  building up
  1094.                 dwThreadPriority = GetThreadPriority(GetCurrentThread());
  1095.                 if(dwThreadPriority < THREAD_PRIORITY_HIGHEST) {
  1096.                     SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
  1097.                 }
  1098.                 bPeeked = TRUE;
  1099.             }
  1100.         }
  1101.         else {
  1102.             break;
  1103.         }
  1104.     }
  1105.     if(bPeeked) {
  1106.         SetThreadPriority(GetCurrentThread(), dwThreadPriority);
  1107.         if(HIWORD(GetQueueStatus(QS_POSTMESSAGE)) & QS_POSTMESSAGE) {
  1108.             if(uMsgId == 0) {
  1109.                 uMsgId = RegisterWindowMessage(TEXT("AMUnblock"));
  1110.             }
  1111.             if(uMsgId != 0) {
  1112.                 MSG msg;
  1113.                 //  Remove old ones
  1114.                 while(PeekMessage(&msg, (HWND)-1, uMsgId, uMsgId, PM_REMOVE)) {
  1115.                 }
  1116.             }
  1117.             PostThreadMessage(GetCurrentThreadId(), uMsgId, 0, 0);
  1118.         }
  1119.     }
  1120.     return dwResult;
  1121. }
  1122.  
  1123. HRESULT AmGetLastErrorToHResult() {
  1124.     DWORD dwLastError = GetLastError();
  1125.     if(dwLastError != 0) {
  1126.         return HRESULT_FROM_WIN32(dwLastError);
  1127.     }
  1128.     else {
  1129.         return E_FAIL;
  1130.     }
  1131. }
  1132.  
  1133. IUnknown* QzAtlComPtrAssign(IUnknown** pp, IUnknown* lp) {
  1134.     if(lp != NULL)
  1135.         lp->AddRef();
  1136.     if(*pp)
  1137.         (*pp)->Release();
  1138.     *pp = lp;
  1139.     return lp;
  1140. }
  1141.  
  1142. /******************************************************************************
  1143.  
  1144. CompatibleTimeSetEvent
  1145.  
  1146.     CompatibleTimeSetEvent() sets the TIME_KILL_SYNCHRONOUS flag before calling
  1147. timeSetEvent() if the current operating system supports it.  TIME_KILL_SYNCHRONOUS
  1148. is supported on Windows XP and later operating systems.
  1149.  
  1150. Parameters:
  1151. - The same parameters as timeSetEvent().  See timeSetEvent()'s documentation in 
  1152. the Platform SDK for more information.
  1153.  
  1154. Return Value:
  1155. - The same return value as timeSetEvent().  See timeSetEvent()'s documentation in 
  1156. the Platform SDK for more information.
  1157.  
  1158. ******************************************************************************/
  1159. MMRESULT CompatibleTimeSetEvent( UINT uDelay, UINT uResolution, LPTIMECALLBACK lpTimeProc, DWORD_PTR dwUser, UINT fuEvent ) {
  1160.     //
  1161.     // Building for Windows XP
  1162.     // -----------------------
  1163.     // If you want to target Windows XP specifically to use its new features, 
  1164.     // you must set WINVER=0x501 in the sample project file.  You must also 
  1165.     // install the Windows XP Platform SDK, however, to ensure that you have the 
  1166.     // latest header files.  For example, this CompatibleTimeSetEvent() method
  1167.     // uses the new TIME_KILL_SYNCHRONOUS flag only if (WINVER >= 0x501).  This flag 
  1168.     // is conditionally defined in the Windows XP Platform SDK in mmsystem.h, 
  1169.     // but only if WINVER is also set to 0x501 when compiling.  To prevent build 
  1170.     // issues, upgrade to the latest version of the Platform SDK.
  1171.     //
  1172.  
  1173. #if WINVER >= 0x0501 
  1174.     {
  1175.         static bool fCheckedVersion = false;
  1176.         static bool fTimeKillSynchronousFlagAvailable = false; 
  1177.  
  1178.         if(!fCheckedVersion) {
  1179.             fTimeKillSynchronousFlagAvailable = TimeKillSynchronousFlagAvailable();
  1180.             fCheckedVersion = true;
  1181.         }
  1182.  
  1183.         if(fTimeKillSynchronousFlagAvailable) {
  1184.             fuEvent = fuEvent | TIME_KILL_SYNCHRONOUS;
  1185.         }
  1186.     }
  1187. #endif // WINVER >= 0x0501
  1188.  
  1189.     return timeSetEvent(uDelay, uResolution, lpTimeProc, dwUser, fuEvent);
  1190. }
  1191.  
  1192. bool TimeKillSynchronousFlagAvailable( void ) {
  1193.     OSVERSIONINFO osverinfo;
  1194.  
  1195.     osverinfo.dwOSVersionInfoSize = sizeof(osverinfo);
  1196.  
  1197.     if(GetVersionEx(&osverinfo)) {
  1198.  
  1199.         // Windows XP's major version is 5 and its' minor version is 1.
  1200.         // timeSetEvent() started supporting the TIME_KILL_SYNCHRONOUS flag
  1201.         // in Windows XP.
  1202.         if((osverinfo.dwMajorVersion > 5) || 
  1203.             ( (osverinfo.dwMajorVersion == 5) && (osverinfo.dwMinorVersion >= 1) )) {
  1204.             return true;
  1205.         }
  1206.     }
  1207.  
  1208.     return false;
  1209. }
  1210.  
  1211.